//
// Dreams Gate Launcher
// www.dg8.ru
//
// GNU GPL v3
//
#include "stdafx.h"

namespace sv {

	int application_console = -1;
	int application_is64 = -1;
	LPFN_ISWOW64PROCESS fnIsWow64Process;

	BOOL is_64bit()
	{
		if (application_is64!=-1)
			return application_is64;

		BOOL bIsWow64 = FALSE;
		fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( GetModuleHandle(TEXT("kernel32")), "IsWow64Process" );

		if(NULL != fnIsWow64Process)
		{
			if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
			{
				// todo
			}
		}

		application_is64 = bIsWow64;
		return bIsWow64;
	}

	BOOL CreateConsole() 
	{
		if (application_console!=-1)
			return application_console;

		if ( AllocConsole() )
		{
			int hCrt = _open_osfhandle( (long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT );
			*stdout = *(::_fdopen(hCrt, "w"));

			::setvbuf(stdout, NULL, _IONBF, 0);
			*stderr = *(::_fdopen(hCrt, "w"));
			::setvbuf(stderr, NULL, _IONBF, 0);

			application_console = 1;
			return TRUE;
		}
		return FALSE;
	}


	/* Display a prompt and read a one-line response into the provided buffer,
	removing a trailing newline if present. */
	static svn_error_t *
		prompt_and_read_line(const char *prompt,
		char *buffer,
		size_t max)
	{
		int len;
		printf("%s: ", prompt);
		if (fgets(buffer, max, stdin) == NULL)
			return svn_error_create(0, NULL, "error reading stdin");
		len = strlen(buffer);
		if (len > 0 && buffer[len-1] == '\n')
			buffer[len-1] = 0;
		return SVN_NO_ERROR;
	}

	/* A tiny callback function of type 'svn_auth_simple_prompt_func_t'. For
	a much better example, see svn_cl__auth_simple_prompt in the official
	svn cmdline client. */
	static svn_error_t *
		my_simple_prompt_callback (svn_auth_cred_simple_t **cred,
		void *baton,
		const char *realm,
		const char *username,
		svn_boolean_t may_save,
		apr_pool_t *pool)
	{
		svn_auth_cred_simple_t *ret = (svn_auth_cred_simple_t*) apr_pcalloc (pool, sizeof (*ret));
		char answerbuf[100];

		if (realm)
		{
			printf ("Authentication realm: %s\n", realm);
		}

		if (username)
			ret->username = apr_pstrdup (pool, username);
		else
		{
			SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
			ret->username = apr_pstrdup (pool, answerbuf);
		}

		SVN_ERR (prompt_and_read_line("Password", answerbuf, sizeof(answerbuf)));
		ret->password = apr_pstrdup (pool, answerbuf);

		*cred = ret;
		return SVN_NO_ERROR;
	}


	/* A tiny callback function of type 'svn_auth_username_prompt_func_t'. For
	a much better example, see svn_cl__auth_username_prompt in the official
	svn cmdline client. */
	static svn_error_t *
		my_username_prompt_callback (svn_auth_cred_username_t **cred,
		void *baton,
		const char *realm,
		svn_boolean_t may_save,
		apr_pool_t *pool)
	{
		svn_auth_cred_username_t *ret = (svn_auth_cred_username_t*)apr_pcalloc (pool, sizeof (*ret));
		char answerbuf[100];

		if (realm)
		{
			printf ("Authentication realm: %s\n", realm);
		}

		SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
		ret->username = apr_pstrdup (pool, answerbuf);

		*cred = ret;
		return SVN_NO_ERROR;
	}


	int UpdateEngine() {
		apr_pool_t *pool;
		svn_error_t *err;
		svn_opt_revision_t revision;
		apr_hash_t *dirents;
		apr_hash_index_t *hi;
		svn_client_ctx_t *ctx;
		const char *URL = "http://svn.dg8.ru/dg8arena/engine/";

		// todo -> FILE *log_errstream;

		CreateConsole();
		printf("Updating please wait...\n");
		if (EXIT_SUCCESS != svn_cmdline_init("svup", stderr ) ) return EXIT_FAILURE;

		/* Create top-level memory pool. Be sure to read the HACKING file to
		understand how to properly use/free subpools. */
		pool = svn_pool_create (NULL);

		/* Initialize the FS library. */
		err = svn_fs_initialize (pool);
		if (err)
		{
			/* For functions deeper in the stack, we usually use the
			SVN_ERR() exception-throwing macro (see svn_error.h).  At the
			top level, we catch & print the error with svn_handle_error2(). */
			svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
			return EXIT_FAILURE;
		}

		/* Make sure the ~/.subversion run-time config files exist */
		err = svn_config_ensure (NULL, pool);
		if (err)
		{
			svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
			return EXIT_FAILURE;
		}

		/* All clients need to fill out a client_ctx object. */
		{
			/* Initialize and allocate the client_ctx object. */
			if ((err = svn_client_create_context (&ctx, pool)))
			{
				svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
				return EXIT_FAILURE;
			}

			/* Load the run-time config file into a hash */
			if ((err = svn_config_get_config (&(ctx->config), NULL, pool)))
			{
				svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
				return EXIT_FAILURE;
			}

#ifdef WIN32
			/* Set the working copy administrative directory name. */
			if (getenv ("SVN_ASP_DOT_NET_HACK"))
			{
				err = svn_wc_set_adm_dir ("_svn", pool);
				if (err)
				{
					svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
					return EXIT_FAILURE;
				}
			}
#endif

			/* Depending on what your client does, you'll want to read about
			(and implement) the various callback function types below.  */

			/* A func (& context) which receives event signals during
			checkouts, updates, commits, etc.  */
			/* ctx->notify_func = my_notification_func;
			ctx->notify_baton = NULL; */

			/* A func (& context) which can receive log messages */
			/* ctx->log_msg_func = my_log_msg_receiver_func;
			ctx->log_msg_baton = NULL; */

			/* A func (& context) which checks whether the user cancelled */
			/* ctx->cancel_func = my_cancel_checking_func;
			ctx->cancel_baton = NULL; */

			/* Make the client_ctx capable of authenticating users */
			{
				/* There are many different kinds of authentication back-end
				"providers".  See svn_auth.h for a full overview.

				If you want to get the auth behavior of the 'svn' program,
				you can use svn_cmdline_setup_auth_baton, which will give
				you the exact set of auth providers it uses.  This program
				doesn't use it because it's only appropriate for a command
				line program, and this is supposed to be a general purpose
				example. */

				svn_auth_provider_object_t *provider;
				apr_array_header_t *providers
					= apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));

				svn_auth_get_simple_prompt_provider (&provider,
					my_simple_prompt_callback,
					NULL, /* baton */
					2, /* retry limit */ pool);
				APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;

				svn_auth_get_username_prompt_provider (&provider,
					my_username_prompt_callback,
					NULL, /* baton */
					2, /* retry limit */ pool);
				APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;

				/* Register the auth-providers into the context's auth_baton. */
				svn_auth_open (&ctx->auth_baton, providers, pool);
			}
		} /* end of client_ctx setup */


		/* Now do the real work. */

		/* Set revision to always be the HEAD revision.  It could, however,
		be set to a specific revision number, date, or other values. */
		revision.kind = svn_opt_revision_head;

		/* Main call into libsvn_client does all the work. */
		err = svn_client_ls (&dirents,
			URL, &revision,
			FALSE, /* no recursion */
			ctx, pool);
		if (err)
		{
			svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
			return EXIT_FAILURE;
		}

		/* Print the dir entries in the hash. */
		for (hi = apr_hash_first (pool, dirents); hi; hi = apr_hash_next (hi))
		{
			const char *entryname;
			svn_dirent_t *val;

			apr_hash_this (hi, (const void **) &entryname, NULL, (void **) &val);
			printf ("   %s\n", entryname);

			/* 'val' is actually an svn_dirent_t structure; a more complex
			program would mine it for extra printable information. */
		}

		return EXIT_SUCCESS;
	}

	CString Format(LPCTSTR format, ...)
	{
		va_list		ap;
		CString		str;

		va_start(ap, format);
		str.FormatV(format, ap);
		va_end(ap);		
		return str;
	}

} // namespace

bool is_file(LPCTSTR fname)
{
	return CFileFind().FindFile(fname) == TRUE;
}
